package com.isoftstone.service.impl;

import cn.hutool.core.io.IoUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.BCrypt;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.isoftstone.controller.StudentController;
import com.isoftstone.mapper.StudentMapper;
import com.isoftstone.pojo.Student;
import com.isoftstone.pojo.dto.PasswordModifyDTO;
import com.isoftstone.pojo.dto.UpdateStudentDormDto;
import com.isoftstone.service.StudentService;
import com.isoftstone.util.BusinessException;
import com.isoftstone.util.ErrorCode;
import com.isoftstone.util.Result;
import com.isoftstone.vo.CountData;
import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class StudentServiceImpl implements StudentService {
    @Autowired
    @Resource
    private StudentMapper studentMapper;
    // 添加日志对象定义（如果尚未定义）
    private static final Logger log = LoggerFactory.getLogger(StudentController.class);

    /**
     * 添加学生
     * @param student 学生信息
     * @return 操作结果
     */
    @Override
    public Result<?> insertStudent(Student student) {
        try {
            // 检查学号是否已存在
            int count = studentMapper.countByStudentNumber(student.getStudentNumber());
            if (count > 0) {
                return Result.error("学号已存在，请重新输入");
            }

            // 插入学生信息
            int result = studentMapper.insertStudent(student);
            if (result > 0) {
                return Result.success("添加学生成功");
            } else {
                return Result.error("添加学生失败");
            }
        } catch (Exception e) {
            // 记录日志
            e.printStackTrace();
            return Result.error("系统异常，添加学生失败");
        }
    }

    //    分页查询
    @Override
    public Page queryAllStudent(Integer currentSize, Integer pageSize) {
        Page page = PageHelper.startPage(currentSize, pageSize);
        studentMapper.queryAllStudent();
        return page;
    }

    @Override
    public Result<?> updateStudent(Student student) {
        // 设置更新时间
        student.setUpdatedAt(new Date());

        // 只更新电话号码、邮箱和地址信息
        // 创建一个新的对象，只包含需要更新的字段，避免意外更新其他字段
        Student updateData = new Student();
        updateData.setStudentNumber(student.getStudentNumber()); // 作为更新条件
        updateData.setPhone(student.getPhone());
        updateData.setEmail(student.getEmail());
        updateData.setAddress(student.getAddress());
        updateData.setUpdatedAt(student.getUpdatedAt());
        updateData.setStatus(student.getStatus());
        // 执行更新操作
        int result = studentMapper.updateStudent(updateData);

        if (result > 0) {
            return Result.success("学生信息修改成功");
        }
        return Result.error("学生信息修改失败");
    }
    @Override
    public Result<?> deleteStudent(Integer id) {
        int result = studentMapper.deleteStudent(id);
        if (result > 0) {
            return Result.success("删除成功");
        }
        return Result.error("删除失败");
    }
    //批量删除用户
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int batchDeleteStudents(List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            return 0;
        }

        // 验证用户是否存在
        List<Long> existingIds = studentMapper.selectExistingStudentIds(ids);
        if (existingIds.size() != ids.size()) {
            List<Long> nonExistingIds = ids.stream()
                    .filter(id -> !existingIds.contains(id))
                    .toList();
            throw new RuntimeException("以下用户不存在: " + nonExistingIds);
        }

        // 执行批量删除
        return studentMapper.batchDeleteStudents(ids);
    }
    @Override
    public Page<Student> searchStudentsByName(String name, Integer currentSize, Integer pageSize) {
        // 设置分页参数
        PageHelper.startPage(currentSize, pageSize);

        // 执行查询
        Page<Student> studentPage = studentMapper.searchStudentsByName(name);

        return studentPage;
    }

    @Override
    public void exportExcel(HttpServletResponse response) throws IOException {
//        1.查询所有用户信息
        List<Student> students = studentMapper.queryAllStudent();
//        通过工具类生成excel文件
        ExcelWriter writer= ExcelUtil.getWriter();
        writer.write(students,true);
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        String fileName = URLEncoder.encode("用户信息", "UTF-8");
//        设置响应头
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
//        获取输出流对象
        ServletOutputStream out=response.getOutputStream();
        writer.flush(out,true);
//        关闭数据流

        writer.close();
        IoUtil.close(out);
    }

    /**
     * 实现：按姓名+报到状态分页查询报到信息
     */
    @Override
    public PageInfo<Student> queryReportInfoByPage(String name, String status, Integer currentPage, Integer pageSize) {
        PageHelper.startPage(currentPage, pageSize);
        // 调用返回Student列表的方法
        List<Student> reportList = studentMapper.selectReportInfoByCondition(name, status);
        return new PageInfo<>(reportList);
    }

    /**
     * 实现：统计系别+专业人数
     */
    @Override
    public Result<?> statisticsDeptAndMajor() {
        try {
            List<CountData> statisticsList = studentMapper.statisticsDeptAndMajor();
            if (statisticsList == null || statisticsList.isEmpty()) {
                log.info("暂无学生数据，统计结果为空");
                return Result.success("暂无学生数据", statisticsList);
            }
            log.info("系别/专业人数统计完成，共{}组数据", statisticsList.size());
            log.info("系别/专业人数统计结果：{}", statisticsList);
            return Result.success("统计成功", statisticsList);
        } catch (Exception e) {
            log.error("系别/专业人数统计失败", e);
            return Result.error("统计失败：" + e.getMessage());
        }
    }

    /**
     * 实现：多条件搜索学生（姓名+系别+专业）
     */
    @Override
    public Result<?> searchStudentsByMultiCond(
            String name, String department, String major,
            Integer currentPage, Integer pageSize
    ) {
        try {
            // 1. 分页参数校验（避免非法值）
            if (currentPage == null || currentPage < 1) currentPage = 1;
            if (pageSize == null || pageSize < 1 || pageSize > 100) pageSize = 1000;

            // 2. 开启分页，调用Mapper
            PageHelper.startPage(currentPage, pageSize);
            Page<Student> studentPage = studentMapper.searchStudentsByMultiCond(name, department, major);

            // 3. 封装分页结果
            PageInfo<Student> pageInfo = new PageInfo<>(studentPage);
            if (pageInfo.getList().isEmpty()) {
                log.info("多条件搜索未找到学生（姓名：{}，系别：{}，专业：{}）", name, department, major);
                return Result.success("未找到符合条件的学生", pageInfo);
            }
            log.info("多条件搜索成功，找到{}条学生数据", pageInfo.getTotal());
            return Result.success("搜索成功", pageInfo);
        } catch (Exception e) {
            log.error("多条件搜索学生失败", e);
            return Result.error("搜索失败：" + e.getMessage());
        }
    }
    /**
     * 实现：修改学生系别和专业
     */
    @Override
    public Result<?> updateDeptAndMajor(Integer id, String department, String major) {
        try {
            // 1. 基础参数校验：ID必传，避免空指针
            if (id == null) {
                return Result.error("学生ID不能为空");
            }
            // 去除参数前后空格，避免“空格视为有效值”的脏数据
            String newDept = (department == null) ? null : department.trim();
            String newMajor = (major == null) ? null : major.trim();

            // 2. 校验学生是否存在（避免修改不存在的学生）
            Student existingStudent = studentMapper.selectStudentById(id);
            if (existingStudent == null) {
                log.warn("修改系别/专业失败：ID为{}的学生不存在", id);
                return Result.error("未找到ID为" + id + "的学生");
            }
            // 获取学生当前的系别和专业（用于对比是否变化）
            String oldDept = existingStudent.getDepartment();
            String oldMajor = existingStudent.getMajor();

            // 3. 核心逻辑：区分“只改专业”和“改系别”场景，校验合法性
            boolean isDeptChanged = (newDept != null && !newDept.equals(oldDept)); // 系别是否要修改
            boolean isMajorChanged = (newMajor != null && !newMajor.equals(oldMajor)); // 专业是否要修改

            // 3.1 非法场景1：修改系别但不修改专业
            if (isDeptChanged && !isMajorChanged) {
                return Result.error("修改系别时必须同步指定新专业（系别与专业需匹配）");
            }
            // 3.2 非法场景2：未传入任何需修改的字段（系别和专业都没变化）
            if (!isDeptChanged && !isMajorChanged) {
                return Result.success("系别和专业未变化，无需修改");
            }
            // 3.3 非法场景3：只改专业但专业参数为空（理论上newMajor已去空格，此处防极端情况）
            if (!isDeptChanged && (newMajor == null || newMajor.isEmpty())) {
                return Result.error("修改专业时必须指定新专业名称");
            }

            // 4. 动态确定要更新的字段（空值不更新，避免覆盖原有正确数据）
            String finalDept = isDeptChanged ? newDept : oldDept; // 系别：要改则用新值，不改则用原值
            String finalMajor = isMajorChanged ? newMajor : oldMajor; // 专业：要改则用新值，不改则用原值

            // 5. 执行修改（调用原Mapper方法，传入最终确定的字段值）
            int updateCount = studentMapper.updateDeptAndMajor(
                    id,
                    finalDept,
                    finalMajor,
                    new Date() // 更新时间戳
            );

            // 6. 处理结果并打印日志（区分场景记录，便于追溯）
            if (updateCount > 0) {
                String logMsg;
                if (isDeptChanged && isMajorChanged) {
                    logMsg = String.format("学生%s（ID：%s）系别+专业修改成功：原系别=%s→新系别=%s，原专业=%s→新专业=%s",
                            existingStudent.getName(), id, oldDept, finalDept, oldMajor, finalMajor);
                } else { // 只改专业
                    logMsg = String.format("学生%s（ID：%s）专业修改成功：原专业=%s→新专业=%s，系别保持为%s",
                            existingStudent.getName(), id, oldMajor, finalMajor, oldDept);
                }
                log.info(logMsg);
                return Result.success(logMsg);
            } else {
                log.error("学生{}（ID：{}）系别/专业修改失败：SQL执行后无数据更新",
                        existingStudent.getName(), id);
                return Result.error("修改失败，请重试");
            }
        } catch (Exception e) {
            log.error("修改学生系别/专业异常（ID：{}）", id, e);
            return Result.error("系统异常：" + e.getMessage());
        }
    }
    @Override
    public Result<Student> findByStudentNumber(String studentNumber) {
        if (studentNumber == null || studentNumber.trim().isEmpty()) {
            return Result.error("学生学号不能为空");
        }

        Student student = studentMapper.findByStudentNumber(studentNumber);
        if (student != null) {
            return Result.success(student);
        } else {
            return Result.error("未找到学号为" + studentNumber + "的学生");
        }
    }

    @Override
    public Result<Student> updateStudentDormitory(String studentNumber, UpdateStudentDormDto dto) {
        // 1. 参数校验
        if (studentNumber == null || studentNumber.trim().isEmpty()) {
            return Result.error("学生学号不能为空");
        }
        if (dto.getDormitoryId() == null || dto.getDormitory() == null) {
            return Result.error("宿舍ID和宿舍信息不能为空");
        }
        // 2. 调用Mapper更新tb_student表
        int rows = studentMapper.updateDormitoryInfo(studentNumber, dto.getDormitoryId(), dto.getDormitory());
        if (rows > 0) {
            return Result.success();
        } else {
            return Result.error("未找到该学生或宿舍信息更新失败");
        }
    }



    /**
     * 学生登录实现类
     */
    @Override
    public Student login(String phone, String password) {
        // 输入参数校验
        if (phone == null || phone.isEmpty()) {
            throw new BusinessException("手机号不能为空");
        }

        if (password == null || password.isEmpty()) {
            throw new BusinessException("密码不能为空");
        }

        // 验证手机号格式
        if (!phone.matches("^1[3-9]\\d{9}$")) {
            throw new BusinessException("手机号格式不正确");
        }

        // 首先根据电话号码查询学生信息
        Student student = studentMapper.findByPhone(phone);

        // 检查学生是否存在
        if (student == null) {
            throw new BusinessException("该学生不存在");
        }

        // 检查该学生是否已设置密码（账号是否已激活）
        if (student.getPassword() == null || student.getPassword().isEmpty()) {
            throw new BusinessException("该账号尚未激活，请先完成注册");
        }

        // 调用Mapper层进行密码验证
        Student loginStudent = studentMapper.login(phone, password);

        // 检查密码是否正确
        if (loginStudent == null) {
            throw new BusinessException("密码错误");
        }

        return loginStudent;
    }
    /**
     * 学生注册功能
     * 业务规则：
     * 1. 仅允许tb_student中已存在的手机号注册
     * 2. 仅允许密码为空的学生进行注册（设置密码）
     * 3. 若手机号不存在 - 提示不存在该学生
     * 4. 若手机号存在且密码已设置 - 提示此账号已注册
     */
    @Override
    @Transactional
    public void register(String phone, String newPassword) {
        // 1. 输入参数校验
        if (!StringUtils.hasText(phone)) {
            log.error("注册失败：手机号为空");
            throw new BusinessException(ErrorCode.PARAM_ERROR);  // 参数错误
        }

        if (!StringUtils.hasText(newPassword)) {
            log.error("注册失败：新密码为空");
            throw new BusinessException(ErrorCode.PARAM_ERROR);  // 参数错误
        }

        // 2. 验证手机号格式
        if (!phone.matches("^1[3-9]\\d{9}$")) {
            log.error("注册失败：手机号格式不正确，手机号：{}", phone);
            throw new BusinessException(ErrorCode.PHONE_FORMAT_ERROR);  // 1003
        }

        // 3. 验证密码强度
        if (newPassword.length() < 6) {
            log.error("注册失败：密码长度不足，手机号：{}", phone);
            throw new BusinessException(ErrorCode.PASSWORD_TOO_SHORT);  // 1004
        }

        // 4. 查询数据库中是否存在该学生
        Student student = studentMapper.findByPhone(phone);
        if (student == null) {
            log.warn("注册失败：手机号不存在，手机号：{}", phone);
            throw new BusinessException(ErrorCode.STUDENT_NOT_FOUND);  // 1001（学生不存在）
        }

        // 5. 检查该学生是否已设置密码（已注册）
        if (StringUtils.hasText(student.getPassword())) {
            log.warn("注册失败：账号已注册，手机号：{}", phone);
            throw new BusinessException(ErrorCode.STUDENT_ALREADY_ACTIVATED);  // 1002（已激活）
        }


        student.setPassword(newPassword);  // 存储加密后的密码

        // 7. 更新数据库
        studentMapper.updateStudent(student);  // 确保此方法实现了更新逻辑

        log.info("注册成功，手机号：{}", phone);
    }
    @Override
    @Transactional
    public void resetPassword(String phone, String newPassword) {
        // 1. 输入参数校验
        if (!StringUtils.hasText(phone)) {
            log.error("重置密码失败：手机号为空");
            throw new BusinessException("手机号不能为空");
        }

        if (!StringUtils.hasText(newPassword)) {
            log.error("重置密码失败：新密码为空");
            throw new BusinessException("新密码不能为空");
        }

        // 2. 验证手机号格式
        if (!phone.matches("^1[3-9]\\d{9}$")) {
            log.error("重置密码失败：手机号格式不正确，手机号：{}", phone);
            throw new BusinessException("手机号格式不正确");
        }

        // 3. 验证密码强度
        if (newPassword.length() < 6) {
            log.error("重置密码失败：密码长度不足，手机号：{}", phone);
            throw new BusinessException("密码长度不能少于6位");
        }

        // 4. 查询数据库中是否存在该学生
        Student student = studentMapper.findByPhone(phone);
        if (student == null) {
            log.warn("重置密码失败：手机号不存在，手机号：{}", phone);
            throw new BusinessException("该手机号未注册");
        }

        // 5. 检查该学生是否已注册（已设置密码）
        if (!StringUtils.hasText(student.getPassword())) {
            log.warn("重置密码失败：账号未注册，无法重置密码，手机号：{}", phone);
            throw new BusinessException("该账号尚未注册，请先完成注册");
        }

        // 6. 【新增】检查新密码是否与旧密码相同
        if (newPassword.equals(student.getPassword())) {
            log.warn("重置密码失败：新密码与旧密码相同，手机号：{}", phone);
            throw new BusinessException("新密码不能与旧密码相同");
        }

        // 7. 更新密码
        studentMapper.updatePassword(student.getStudentNumber(), newPassword);

        log.info("密码重置成功，手机号：{}", phone);
    }
    @Override
    public void updateAvatarUrl(String studentNo, String avatarUrl) {
        // 可在此处添加额外业务逻辑，如参数校验
        if (studentNo == null || studentNo.trim().isEmpty()) {
            throw new IllegalArgumentException("学生学号不能为空");
        }
        if (avatarUrl == null || avatarUrl.trim().isEmpty()) {
            throw new IllegalArgumentException("头像URL不能为空");
        }
        // 调用Mapper执行数据库更新
        studentMapper.updateAvatarUrl(studentNo, avatarUrl);
    }
    @Override
    public Result modifyPassword(String studentNumber, PasswordModifyDTO dto) {
        // 1. 验证新密码和确认密码是否一致
        if (!dto.getNewPassword().equals(dto.getConfirmPassword())) {
            return Result.error("两次输入的新密码不一致");
        }

        // 2. 验证密码长度
        if (dto.getNewPassword().length() < 6) {
            return Result.error("新密码长度不能少于6位");
        }

        // 3. 根据学号查询学生信息
        Student student = studentMapper.selectByStudentNumber(studentNumber);
        if (student == null) {
            return Result.error("学生不存在");
        }

        // 4. 验证原密码是否正确（不加密直接比对）
        if (!student.getPassword().equals(dto.getOldPassword())) {
            return Result.error("原密码不正确");
        }

        // 5. 设置新密码（不加密存储）
        student.setPassword(dto.getNewPassword());
        student.setUpdatedAt(new Date());

        // 6. 更新数据库
        int rows = studentMapper.updateById(student);
        if (rows > 0) {
            return Result.success("密码修改成功");
        } else {
            return Result.error("密码修改失败");
        }
    }


    /**
     * 根据学号查询学生及关联的宿舍详细信息（含可住人数和当前入住人数）
     */
    @Override
    public Result<Student> getStudentWithDormDetail(String studentNumber) {
        Student student = studentMapper.findByStudentNumber(studentNumber);
        if (student == null) {
            return Result.error("学生不存在");
        }
        return Result.success(student);
    }

    @Override
    public Result<Student> getStudentWithDormitory(String studentNumber) {
        try {
            if (StringUtils.isEmpty(studentNumber)) {
                return Result.error("学号不能为空");
            }

            Student student = studentMapper.selectStudentWithDormitoryByNumber(studentNumber);
            if (student == null) {
                return Result.error("未找到该学生信息");
            }

            return Result.success(student);
        } catch (Exception e) {
            log.error("查询学生及宿舍信息失败", e);
            return Result.error("查询失败：" + e.getMessage());
        }
    }

}

